package cn.yhjz.platform.system.util;

import cn.yhjz.platform.system.entity.SysUser;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

@Slf4j
@Component
public class TokenUtil {

    //超时时间，秒
    @Value("${system.redis-token-timeout}")
    private Integer redisTokenTimeout;
    //证书发行人
    private static String ISSUER_NAME = null;
    private static String tokenSalt = null;


    @Value("${system.salt}")
    public void setSalt(String salt) {
        TokenUtil.tokenSalt = salt;
    }

    @Value("${system.issuer-name}")
    public void setIssuerName(String issuerName) {
        TokenUtil.ISSUER_NAME = issuerName;
    }

    /**
     * 创建签名token
     *
     * @return
     */
    public String createToken(SysUser user) {
        String token = null;
        Date nowDate = new Date();
        Date expireAt = Date.from(LocalDateTime.now().plusSeconds(redisTokenTimeout * 3).atZone(ZoneId.systemDefault()).toInstant());
        token = JWT.create()
                //设置证书发行人
                .withIssuer(ISSUER_NAME)
                //自定义信息。设置用户名
                .withClaim("usercode", user.getUserCode())
                .withClaim("username", user.getUsername())
                //自定义信息。设置用户的昵称
                .withClaim("nickname", user.getNickname())
                //设置整数签发时间
                .withIssuedAt(nowDate)
                .withExpiresAt(expireAt)
                .sign(Algorithm.HMAC256(tokenSalt));
        return token;
    }

    /**
     * 验证签名
     *
     * @param token
     * @return
     */
    public SysUser verify(String token) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenSalt)).withIssuer(ISSUER_NAME).build();
            DecodedJWT jwt = verifier.verify(token);
            SysUser user = new SysUser();
            user.setUserCode(jwt.getClaim("usercode").asString());
            user.setUsername(jwt.getClaim("username").asString());
            user.setNickname(jwt.getClaim("nickname").asString());
            return user;
        } catch (TokenExpiredException expiredException) {
            log.info("token已过期");
            return null;
        } catch (SignatureVerificationException verificationException) {
            log.info("token签名校验失败");
            return null;
        } catch (Exception exception) {
            log.error("token验证异常：{}", exception);
            return null;
        }
    }

    /**
     * 判断token是否快要过期
     *
     * @param token
     * @return SysUser 如果快要过期就返回SysUser对象，用于重新生成token
     */
    public SysUser near(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            Instant expiresAt = jwt.getExpiresAtAsInstant();
            Instant nowInstant = Instant.now();
            Instant timerAfter = nowInstant.plusSeconds(redisTokenTimeout);
            //即将过期
            if (timerAfter.isAfter(expiresAt)) {
                SysUser user = new SysUser();
                user.setUserCode(jwt.getClaim("usercode").asString());
                user.setUsername(jwt.getClaim("username").asString());
                user.setNickname(jwt.getClaim("nickname").asString());
                return user;
            }
        } catch (JWTDecodeException decodeException) {
            log.info("解析token失败");
            return null;
        }
        return null;
    }
}
